x日以上ログインしていないIAMユーザーを特定し通知する仕組みを考えてみた
はじめに
こんにちは。AWS事業本部コンサルティング部に所属している和田響です。
この記事ではAWSにおけるIAMユーザの管理の一環として、非アクティブなIAMユーザーを特定し通知する仕組みの一例を紹介します。
IAMユーザー放置の危険性
IAMユーザーは存在するだけで不正ログインの可能性があること忘れてはいけません。
その可能性を少しでも0に近づけるために、強力なパスワードの設定、MFAデバイスの割り当て、最小権限化を行うわけですが、そもそもIAMユーザーが存在しなければこのようなリスクは存在しません。
つまりは、非アクティブなIAMユーザーを放置するということは、不用意に不正のリスクを上げていることに他なりません。
また、クレジットカード業界のセキュリティ基準であるPCI DSSでは 最後のアクティビティから90日以上たったアカウントは削除または無効化することを求めています。
定義されたアプローチの要件
8.2.6 非アクティブなユーザアカウントは、非アクティブ化された日から 90 日以内に削除または無効化される。
引用:https://listings.pcisecuritystandards.org/documents/PCI-DSS-v4_0-JA.pdf
構成
今回はLambdaで「x日以上ログインしているIAMユーザーが存在する場合に、SNSに通知する」スクリプトを実行し、EventBridgeでスケジューリングする構成を実装してみます。
SecurityHubで「90日間使用されていないIAMユーザー」を検知することができますが、今回は90日という日数の変更を想定してLambdaでスクリプトを実行してみます。
やってみる
SNSトピック作成
まずはSNSトピックを作成し、通知先への動線を作ります。
SNSのコンソールを開き、サイドタブから「トピック」をクリックします。
「トピックの作成」をクリックし、
任意の名前と表示名を入力し、
「トピックの作成」をクリックします。
トピックの作成が完了したら、ARNをメモしおき、「サブスクリプションの作成」をクリックします。
通知先を入力し「サブスクリプションの作成」をクリックします。
今回は自分のメールアドレス宛に通知したいので、プロトコルはE メール
を選択し、エンドポイントに通知先のメールアドレス
を入力します。
ステータスが「保留中の確認」になっていると思います。
先ほどエンドポイントに設定したメールアドレスに届いているAWS Notification - Subscription Confirmation
というタイトルのメールに記載されているConfirm subscriptionをクリックします。
「Subscription confirmed!」の記載を確認し、
ステータスが「確認済み」になっていることを確認します。
これでSNSの設定は完了です。
IAMロールの作成
続いてLambdaを実行するためのIAMロールを作成します。
IAMのコンソールを開き、「ロール」をクリックし
「ロールの作成」をクリックします。
「ユースケース」にLambda
を選択し、「次へ」をクリックします。
IAMReadOnlyAccess
とAmazonSNSFullAccess
のポリシーを選択し、「次へ」をクリックします。
任意の「ロール名」を入力し、
IAMReadOnlyAccess
とAmazonSNSFullAccess
のポリシーが選択されていることを確認し、「ロールの作成」をクリックします。
Lambda関数の作成
続いてLambda関数を作成していきます。
Lambdaのコンソールを開き、「関数の作成」をクリックします。
「関数名」に任意の値を入力、ランタイムに実行したい言語(今回はPython
を選択)を選択し、既存のロールに先ほど作成したIAMロールを選択し、「関数の作成」をクリックします。
今回はLambdaで以下のスクリプトをLambdaで実行していきます。
前述のPCI DSSの要件に合わせて90日以上ログインしていないIAMユーザーを特定する想定です。
import boto3 from datetime import datetime, timezone, timedelta def lambda_handler(event, context): # AWSクライアントの初期化 iam = boto3.client('iam') sns = boto3.client('sns') # SNSトピックARN sns_topic_arn = 'arn:aws:sns:region:account-id:topic-name' # 現在の日時を取得 now = datetime.now(timezone.utc) # 90日前の日時を計算 threshold_date = now - timedelta(days=90) try: # IAMユーザーリストを取得 users = iam.list_users()['Users'] except Exception as e: print(f"Error retrieving IAM users: {e}") raise e inactive_users = [] for user in users: user_name = user['UserName'] print(f"Checking user: {user_name}") if 'PasswordLastUsed' in user: last_used = user['PasswordLastUsed'] print(f"User {user_name} last used password on: {last_used}") else: # 最終ログイン日時がない場合はスキップ print(f"User {user_name} has no record of password usage.") continue # 最終ログイン日時が90日以上前かどうかを確認 if last_used < threshold_date: inactive_users.append(user_name) if inactive_users: message = f"以下のIAMユーザーは90日以上ログインしていません:\n" + "\n".join(inactive_users) print(f"Sending SNS notification with message: {message}") try: sns.publish( TopicArn=sns_topic_arn, Message=message, Subject='非アクティブなIAMユーザー通知' ) except Exception as e: print(f"Error sending SNS notification: {e}") raise e return "Script execution completed."
このスクリプトの以下2点を変更し、コードソースに貼り付け、「Deploy」をクリックします。
1.arn:aws:sns:region:account-id:topic-name
を先ほどメモしたSNSトピックのARNに置き換える
2.検証のためthreshold_date = now - timedelta(days=90)
をthreshold_date = now - timedelta(days=0)
に変更する
続いてタブから「設定」をクリックし、
「編集」をクリックし、
「タイムアウト」を変更し、「保存」をクリックします。
デフォルトの3秒では完了する前にタイムアウトになってしまうので、1分に設定します。
ここまで完了したら、Lambdaをテストしていきます。
コードソースから「Test」をクリックします。
"Script execution completed."
より無事に実行たことがわかります。
エンドポイントに設定しているメールアドレスに「非アクティブなIAMユーザー通知」という件名でメールが来ていれば成功です。
先ほどテスト用にスクリプトを変更したので、「最後のログインから0日以上ログインしたユーザーを通知」しているので、アカウント内に存在するすべてのIAMユーザーが表示されているはずです。
このタイミングで、スクリプトを正しい日数に修正しましょう。
EventBridgeの設定
ここまでで「最後のログインから90日以上ログインしたユーザーを通知する」ことはできたので、最後にEventBridgeスケジュールの設定を行います。
EventBridgeのコンソールを開き、サイドタブから「スケジュール」をクリックします。
「スケジュールを作成」をクリックします。
任意の「スケジュール名」と「説明」を入力し、
スケジュールのパターンを入力(画像は毎日0時に実行するcronを設定)し、
「次へ」をクリックします。
ターゲットに「AWS Lambda」を選択し、
先ほど作成したLambda関数を選択し、「次へ」をクリックします。
「スケジュール完了後のアクション」を選択し、
それ以外はデフォルトの設定で「次へ」をクリックします。
内容を確認し、「スケジュールの作成」をクリックします。
次の日まで待って、EventBridgeで指定したcron通りにメールが届いていれば設定完了です。
最後に
今回は非アクティブなIAMユーザーを特定し通知する仕組みの一例を紹介しましたが、あくまで通知を行うだけです。
システム要件で削除や権限剥奪が必要な場合は、スクリプトや運用方法の変更を検討していきましょう。
この記事がどなたかの役に立てれば幸いです。